package pCloud.server;

import pCloud.client.ClientProxyServerConnector;
import pCloud.client.ProxyServerDataServerConnector;
import pCloud.config.PCloudConfig;
import pCloud.service.CachingHandle;
import pCloud.service.DataCaching;
import pCloud.service.IncompleteResponse;
import pCloud.service.ProtocolHandle;
import pCloud.transport.Communicator;
import pCloud.transport.SocketCommunicator;

import java.net.InetSocketAddress;
import java.util.HashMap;
import java.util.Iterator;

import org.apache.log4j.FileAppender;
import org.apache.log4j.Logger;
import org.apache.log4j.SimpleLayout;

/**
 * Impelementing the Proxy server, which serves requests from the clients and
 * connects to the data servers to forward the client's requests.
 * 
 * 1. Create a list of out-going connections to the data servers. 2. Listen for
 * client connections 3. Forward request from client to the data server (Do all
 * caching, parsing here) 4. Wait for response from the data server, do the
 * caching, aggregation then forward back to the client.
 * 
 */
public class ProxyServer {

	int listeningPort;
	int serverId = 0;
	Logger logger;
	Communicator communicator;
	IncompleteResponse incompleteResponses;
	CachingHandle cachingHandler;

	public ProxyServer(int port, int serverId) {
		this.listeningPort = port;
		this.serverId = serverId;
		this.communicator = new SocketCommunicator();
	}

	public void init() throws NumberFormatException, Exception {
		logger = initLog("ProxyServer" + serverId,
				PCloudConfig.PCLOUD_PROXY_SERVER_LOG);
		this.communicator.init(logger);

		this.incompleteResponses = new IncompleteResponse();

		this.cachingHandler = new DataCaching(20);

		this.connectToDataServer();
		this.acceptingClientConnections();

	}

	Logger initLog(String name, String output) {
		Logger logger = Logger.getLogger(name);
		SimpleLayout layout = new SimpleLayout();

		FileAppender appender = null;
		try {
			appender = new FileAppender(layout, PCloudConfig.getString(output),
					false);
		} catch (Exception e) {
		}

		logger.addAppender(appender);
		return logger;
	}

	private void connectToDataServer() throws NumberFormatException, Exception {
		String[] dS = PCloudConfig.getString(
				PCloudConfig.PCLOUD_DATA_SERVER_ADDRESS).split(" ");
		int nDataServers = new Integer(dS[0]).intValue();

		int j = 1;
		InetSocketAddress[] addresses = new InetSocketAddress[nDataServers];
		ProxyServerDataServerConnector connector;

		for (int i = 0; i < nDataServers; i++) {
			addresses[i] = new InetSocketAddress(dS[j],
					new Integer(dS[j + 1]).intValue());

			connector = new ProxyServerDataServerConnector(dS[j], new Integer(
					dS[j + 1]).intValue(), this.communicator,
					this.cachingHandler, this.incompleteResponses);

			connector.connect();
			communicator.addConnection(connector.protocolHandler);
			j += 2;
		}
	}

	void acceptingClientConnections() throws Exception {
		new ProxyServerAcceptor(this.listeningPort, this.communicator,
				this.cachingHandler, this.incompleteResponses).accept();
	}

	public static void main(String[] args) throws Exception {
		String configFile = PCloudConfig.DEFAULT_CONFIG_FILE;
		if (args.length > 0)
			configFile = args[0];

		PCloudConfig.init(configFile);
		String[] addr = PCloudConfig.getString(
				PCloudConfig.PCLOUD_PROXY_SERVER_ADDRESS).split(" ");

		int serverPort = new Integer(addr[1]).intValue();

		ProxyServer ps = new ProxyServer(serverPort, 0);
		ps.init();
	}
}
